//
//  RXDog.m
//  Learn-runtime
//
//  Created by srxboys on 2021/4/15.
//
/**
 OC 方法有哪几个部分组成 ( class_addMethod )
 
     SEL 方法编号 - 方法/函数
     IMP 方法实现 - 函数指针 (就是指针)
     types 返回描述方法参数和返回类型的字符串

 */

#import "RXDog.h"
#import <objc/runtime.h>

@implementation RXDog

// 消息转发 (网上有 三部曲)
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    // 添加eat方法
//    class_addMethod(Class  _Nullable __unsafe_unretained cls, SEL  _Nonnull name, IMP  _Nonnull imp, const char * _Nullable types)
    
    // 无参数
//    class_addMethod(self, sel, eat, "");
    
    // 有参数
    class_addMethod(self, sel, eat, "");
    
    return  [super resolveInstanceMethod:sel];
}

// 无参数
//void eat () {
//    NSLog(@"开始吃饭了");
//}

// 有参数，oc 方法会传递 2个隐式参数
void eat(id self, SEL _cmd, NSString *objc) {
    NSLog(@"开始吃饭了 -> %@", objc);
}
@end


/**
 addMethod(
     Class cls, 地址、指针
     SEL name, 方法、结构体
     IMP imp,  方法地址、函数指针
     const char *types,
     bool replace  是否替换 NO
 )
 
 
 static IMP
 addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)
 {
     IMP result = nil;

     runtimeLock.assertLocked();

     checkIsKnownClass(cls);
     
     ASSERT(types);
     ASSERT(cls->isRealized());

     method_t *m;
     if ((m = getMethodNoSuper_nolock(cls, name))) {
         // already exists
         if (!replace) {
             result = m->imp(false);
         } else {
             result = _method_setImplementation(cls, m, imp);
         }
     } else {
         auto rwe = cls->data()->extAllocIfNeeded();

         // fixme optimize
         method_list_t *newlist;
         newlist = (method_list_t *)calloc(method_list_t::byteSize(method_t::bigSize, 1), 1);
         newlist->entsizeAndFlags =
             (uint32_t)sizeof(struct method_t::big) | fixed_up_method_list;
         newlist->count = 1;
         auto &first = newlist->begin()->big();
         first.name = name;
         first.types = strdupIfMutable(types);
         first.imp = imp;

         prepareMethodLists(cls, &newlist, 1, NO, NO);
         rwe->methods.attachLists(&newlist, 1);
         flushCaches(cls);

         result = nil;
     }

     return result;
 }
 
 
 
 
 _class_addMethod(
     Class cls, 地址、指针
     SEL name, 方法、结构体
     IMP imp,  方法地址、函数指针
     const char *types,
     bool replace  是否替换 NO
 )
 
 
// class_addMethod
 static IMP _class_addMethod(Class cls, SEL name, IMP imp,
                             const char *types, bool replace)
 {
     old_method *m;
     IMP result = nil;

     if (!types) types = "";

     mutex_locker_t lock(methodListLock);

     if ((m = _findMethodInClass(cls, name))) {
         // already exists
         // fixme atomic
         result = method_getImplementation((Method)m);
         if (replace) {
             method_setImplementation((Method)m, imp);
         }
     } else {
         // fixme could be faster
         old_method_list *mlist =
             (old_method_list *)calloc(sizeof(old_method_list), 1);
         mlist->obsolete = fixed_up_method_list;
         mlist->method_count = 1;
         mlist->method_list[0].method_name = name;
         mlist->method_list[0].method_types = strdup(types);
         mlist->method_list[0].method_imp = imp;
         
         _objc_insertMethods(cls, mlist, nil);
         if (!(cls->info & CLS_CONSTRUCTING)) {
             flush_caches(cls, NO);
         } else {
             // in-construction class has no subclasses
             flush_cache(cls);
         }
         result = nil;
     }

     return result;
 }

 */
